perm filename TELSER.MID[NET,MRC]2 blob
sn#339545 filedate 1978-03-05 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00015 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 TITLE TELSER
C00004 00003 Data area
C00006 00004 TELNET protocol codes
C00009 00005 Interrupt server
C00011 00006 Start of program
C00013 00007 Log this connection
C00015 00008 Initialize the connection
C00017 00009 Network input interrupt
C00019 00010 PTY input interrupt
C00020 00011 IAC server
C00022 00012 Protocol command routines
C00024 00013 IAC DO/DONT
C00027 00014 IAC WILL/WONT
C00028 00015 Subroutines
C00031 ENDMK
C⊗;
TITLE TELSER
SUBTTL Definitions
; Mark Crispin, SU-AI, March 1978
; Assembly switches
IFNDEF SVRSKT,SVRSKT==27 ; default listen socket
IFNDEF LOKTMO,LOKTMO==5 ; # of 15-second frobs of lock timeout
IFNDEF PDLLEN,PDLLEN==50 ; stack length
; AC definitions. 0→3 are used by NETWRK
X=4 ? A=5 ? B=6 ? P=17
; Macro to send a TELNET command
DEFINE TELCMD CMDLST
OUTSTR [ASCIZ/⊗!CMDLST!*
/]
IRPS CMD,,CMDLST
MOVEI CMD
PUSHJ P,NETOCH
TERMIN
PUSHJ P,NETSND
TERMIN
; SAIL system bit definitions
INTPTO==001000,, ; PTY interrupt
INTCLK==000200,, ; clock interrupt
DMLIN== 040000,, ; terminal is a Datamedia
ECHARR==010000,, ; echo controls with uparrow
IMPBIT==001000,, ; IMP TTY
FCS== 000020,, ; full character set mode
TBXPND==000010,, ; expand tabs to spaces
FULTWX==000004,, ; no echo
TLKRNG==000001,, ; TALKing
SUBTTL Data area
; TTYSET command words
ECHON: 002400,,(FULTWX) ; echo on
ECHOFF: 001400,,(FULTWX) ; echo off
GAGOFF: 024400,,0 ; gag off
; Terminal location string
TERMID: 'TERMID
CORBEG==. ; start of initialized core storage
TERSTR: BLOCK 10. ; console location string
; Interrupt flags
PTINTP: BLOCK 1 ; -1 → PTI interrupt
NTINTP: BLOCK 1 ; -1 → NTI interrupt
NTOINP: BLOCK 1 ; -1 → INS interrupt
; Protocol flags
NETCMP: BLOCK 1 ; -1 → IAC in progress
IRPS OPT,,WILL WONT DO DONT
OPT!P: BLOCK 1 ; -1 → option in effect
TERMIN
RCBINP: BLOCK 1 ; -1 → receiving binary
TRBINP: BLOCK 1 ; -1 → transmitting binary
ECHOP: BLOCK 1 ; -1 → remote echoing
SUPGAP: BLOCK 1 ; -1 → suppressing GA
; Other flags
TIPP: BLOCK 1 ; -1 → on a TIP
NODETP: BLOCK 1 ; -1 → don't detach this guy
NEWLNP: BLOCK 1 ; -1 → starting newline
LFFLSP: BLOCK 1 ; -1 → PTISER's LF flush kludge
; Other storage
TTYLIN: BLOCK 1 ; line number of PTY
IDLTIM: BLOCK 1 ; idle time in 15-second units
WHOBUF: BLOCK 22 ; wholine buffer
PDL: BLOCK PDLLEN ; stack
COREND==.-1 ; end of initialized storage
SUBTTL TELNET protocol codes
DEFINE TPC CODE
CODE
IRPS NAME,,CODE
[ASCIZ/NAME/]
.ISTOP
TERMIN
TERMIN
; Protocol codes
TPLTAB:
TPC SE==360 ; subnegotiation end
TPC NOP==361 ; no-op
TPC DM==362 ; data mark
TPC BRK==363 ; break key
TPC IP==364 ; interrupt process
TPC AO==365 ; abort output
TPC AYT==366 ; are you there?
TPC EC==367 ; erase character
TPC EL==370 ; erase line
TPC GA==371 ; go ahead
TPC SB==372 ; subnegotiation
TPC WILL==373 ; sender will do
TPC WONT==374 ; sender won't do
TPC DO==375 ; receiver asked to do
TPC DONT==376 ; receiver must not do
TPC IAC==377 ; interpret as command
TPLMIN==400-<.-TPLTAB>
; WILL/WONT/DO/DONT codes
WDOTAB:
TPC TRNBIN==0 ; transmit binary
TPC ECHO==1 ; echo
TPC RCP==2 ; reconnect
TPC SUPRGA==3 ; suppress GA
TPC NAMS==4 ; negotiate approx. message size
TPC STATUS==5 ; status option
TPC TIMMRK==6 ; timing mark
TPC RCTE==7 ; remote controlled trans/echo
TPC NAOL==10 ; negotiate output line width
TPC NAOP==11 ; negotiate page size
TPC NAOCRD==12 ; negotiate output CR
TPC NAOHTS==13 ; negotiate output horizontal tab stops
TPC NAOHTD==14 ; negotiate output HT
TPC NAOFFD==15 ; negotiate output FF
TPC NAOVTS==16 ; negotiate output vertical tab stops
TPC NAOVTD==17 ; negotiate output VT
TPC NAOLFD==20 ; negotiate output LF
TPC EXTASC==21 ; Tovar's idea of extended ASCII
TPC LOGOUT==22 ; logout option
TPC BM==23 ; byte macro
TPC DET==24 ; data entry terminal option
TPC SUPDUP==25 ; SUPDUP (not TELNET) protocol
WDOMAX==.-WDOTAB-1
EXOPL==377 ; extended options (great idea Postel)
SUBTTL Interrupt server
; Interrupts only set flags which the main program (normally in INTW⊗
; state) looks at.
INTSER: SKIPN X,JOBCNI ; get interrupt status
JRST 4,.-1
TLNE X,(INTPTO) ; PTY int
SETOM PTINTP
TLNE X,(INTCLK) ; CLK int
JRST CLKSER
TLNE X,(INTINP) ; NTI int
SETOM NTINTP
TLNE X,(INTIMS) ; status change
JRST INTDIE
TLNE X,(INTINR)
OUTSTR [ASCIZ/*INR*
/]
TLNN X,(INTINS) ; IMP INS int
DISMIS
SOS NTOINP
OUTSTR [ASCIZ/*INS*
/]
DISMIS
; Service clock interrupt
CLKSER: AOSE IDLTIM ; bump idle time
JRST CLKSR1
UNLOCK ; idle timeout; unlock
MOVE TTYLIN
PTGETL
TLNE 1,(TLKRNG) ; TALKing?
JRST CLKSR1 ; don't kill him if so!
TTYJOB
JUMPN CLKSR1
SETOM NODETP ; forget about detaching
INTMSK [0] ; no more interrupts
DEBREAK ; out of interrupt level
TLNN 1,(DMLIN)
JRST DIEDIE ; not a DM, just die
MOVEI ↑X ; cancel modes
PUSHJ P,NETOCH
MOVEI ↑] ; scroll on
PUSHJ P,NETOCH
PUSHJ P,NETSND ; cursor to bottom of screen and roll on
JRST DIEDIE
CLKSR1: MOVEI 2 ; check connection status
MTAPE NET,
TLNN 1,(CLSS\CLSR) ; send side gronked?
TLNE 2,(CLSS\CLSR) ; receive side?
JRST INTDIE
DISMIS
SUBTTL Start of program
TELSER: JFCL
RESET
MOVE ['TELSER]
SETNAM
SETZM CORBEG
MOVE [CORBEG,,CORBEG+1]
BLT COREND
MOVE P,[PDL(-PDLLEN)]
MOVEI [DEBREAK ? EXIT]
MOVEM JOBAPR
CLKINT 5.*60.*60. ; must die if around too long
OUTSTR [ASCIZ/TELSER started
/]
; Listen for a connection on our socket
SETOM NODETP ; don't try to detach
MOVEI SVRSKT
MOVEM LSNSKT
PUSHJ P,LISTEN
; Set up interrupts
MOVEI INTSER
MOVEM JOBAPR ; set up server location
CLKINT 60.*15. ; start slow ticking clock
MOVSI (INTPTO\INTCLK\INTINR\INTINS\INTIMS\INTINP)
INTENB ; turn on interrupts
; Set up terminal id for interested spies
MOVEI TERMID
MOVEM JOBVER
SUBTTL Log this connection
OUTSTR [ASCIZ/Connected to /]
PUSHJ P,MAPHST ; map in host table
MOVE HOST
PUSHJ P,HSTNUM ; get HDB
JFCL ; sorry about errors
MOVEI A,(1) ; host name
HRLI A,440700
SKIPA X,[440700,,TERSTR]
CPYHST: IDPB B,X
ILDB B,A
JUMPN B,CPYHST
HLRZ A,1 ; pointer to system name
MOVE B,(A) ; get system name
MOVE A,FSOCKT ; and ICP socket
CAMN B,[ASCII/TIP/] ; on a TIP?
TRNE A,177774 ; just paranoia; make sure a TIP port
JRST NOTTIP
SETOM TIPP
MOVEI B,"#
IDPB B,X
LSH A,-16.
IDIVI A,8. ; ports are octal
JUMPE A,1DIGTP
ADDI A,"0 ? IDPB A,X
1DIGTP: ADDI B,"0 ? IDPB B,X
NOTTIP: PUSHJ P,SETANM ; set our alias name
PUSHJ P,UNMHST ; map out the host table
OUTSTR TERSTR
OUTSTR [ASCIZ/
/]
SUBTTL Initialize the connection
; Initial protocol commands
TELCMD [IAC WILL ECHO IAC WILL SUPRGA]
SETOM ECHOP ? SETOM SUPGAP
; Greet the user
MOVEI X,[ASCIZ/SU A.I. Lab KL-10
/]
PUSHJ P,SNDMSG
; Get a PTY, keep its number in A
PTYGET A
JRST [ MOVEI X,[ASCIZ/All network ports in use.
/]
PUSHJ P,SNDMSG
PUSHJ P,CLOSER
JRST SUICID]
HRRZM A,TTYLIN ; dumb interrupts
MOVSI (A)
IRPS FOO,,ECHON ECHOFF GAGOFF
IORM FOO
TERMIN
MOVSI B,(ECHARR\IMPBIT\FCS\TBXPND)
PTSETL A ; set initial bits
HRROI GAGOFF
TTYSET ; turn GAG bit off
MOVEI B,↑M
PTWR1W A
; Final initialization
MOVNI 1,LOKTMO
MOVEM 1,IDLTIM ; initialize lock timeout
LOCK ; keep response good
SETZM NODETP ; okay to detach jobs now
JRST NTISER ; check network input
; Main program loop
MAINL: IWAIT ; wait for an interrupt
MAINL0: AOSG NTINTP ; net input?
JRST NTISER
AOSG PTINTP ; PTY input?
JRST PTISER
JRST MAINL ; back to sleep for us
SUBTTL Network input interrupt
NTISER: PUSHJ P,NETICH ; get character from the network
JRST MAINL0 ; network input buffer empty
SKIPL IDLTIM
LOCK
MOVNI 1,LOKTMO
MOVEM 1,IDLTIM ; reset idle time
AOSG NETCMP ; IAC in progress?
JRST IACSER
IRPS OPT,,WILL WONT DO DONT
AOSG OPT!P
JRST OPT!SR
TERMIN
CAIN IAC ; network command?
JRST [ SETOM NETCMP ; remember that one is coming
JRST NTISER]
AOSE NEWLNP ; flush second half of NL?
JRST NTISR2
SKIPE TIPP ; TIPs send neither LF's nor
SKIPN RCBINP ; nulls in binary mode (but Tenices do)
JUMPE NTISER ; yah, flush nulls or
CAIN ↑J ; LFs
JRST NTISER
NTISR2: CAIE ↑M ; CR?
JRST NTISR1
SKIPN ECHOP ; if in local mode
SETOM LFFLSP ; kludge to prevent system echo of LF's
SETOM NEWLNP ; maybe flush an LF
NTISR1: SKIPGE NTOINP ; still in flushify mode?
JRST NTISER ; too bad
MOVE B,
PTYSND: PTWR1S A ; send character to PTY
JRST [ PUSHJ 17,NETINS ; buffer full, send INS
TELCMD [IAC AO IAC DM] ; tell user to flush output
MOVEI ↑G ; bell
PUSHJ 17,NETOCH
PUSHJ 17,NETSND ; output it
JRST NTISER]
JRST NTISER ; try for more user characters
SUBTTL PTY input interrupt
PTISER: PTRD1S A ; get a character from the PTY
JRST MAINL0 ; PTY input buffer empty
SKIPGE IDLTIM
LOCK
PTISR1: MOVNI 1,LOKTMO
MOVEM 1,IDLTIM ; reset idle time
MOVE B
ANDI 377 ; flush funny 400 bit
CAIN ↑J ; LF? (someday remove this kludge)
AOSE LFFLSP ; yes, second part of NL?
PUSHJ P,NETOCH ; send character to net
CAIN IAC ; IAC needs quoting
PUSHJ P,NETOCH
PTRD1S A ; try for more while here
CAIA
JRST PTISR1 ; more coming
PUSHJ P,NETSND ; force buffer out
JRST MAINL0 ; scan the world again
SUBTTL IAC server
IACSER: OUTSTR [ASCIZ/*IAC /]
CAIGE TPLMIN ; big enough?
JRST @RNDMSG
MOVE 1,
OUTSTR @TPLTAB-TPLMIN(1)
CAIE IAC
CAIGE WILL
OUTSTR [ASCIZ/*
/]
CAIL TPLMIN
XCT PRSTAB-TPLMIN(1)
JRST NTISER
DEFINE NC CODE,SERVER
IFN .+TPLMIN-PRSTAB-CODE,.ERR Lossage at CODE
SERVER
TERMIN
PRSTAB: ; Protocol command server table
NC SE,[JRST NTISER]
NC NOP,[JRST NTISER]
NC DM,[AOS NTOINP]
NC BRK,[JRST HALTJB]
NC IP,[JRST HALTJB]
NC AO,[JRST ORESET]
NC AYT,[JRST WHOLIN]
NC EC,[JRST DELCHR]
NC EL,[JRST DELLIN]
NC GA,[JRST NTISER]
NC SB,[JRST NTISER]
NC WILL,[SETOM WILLP]
NC WONT,[SETOM WONTP]
NC DO,[SETOM DOP]
NC DONT,[SETOM DONTP]
NC IAC,[JRST NTISR1]
SUBTTL Protocol command routines
; IAC IP/IAC BRK
HALTJB: MOVEI B,[.BYTE 9 ? 600 ? 600 ? 0]; CALL
PTWRS9 A
JRST NTISER
; IAC AO
ORESET: MOVEI B,↑O
PTWR1W A
OUTSTR [ASCIZ/⊗INS*
/]
PUSHJ P,NETINS ; send SYNCH
TELCMD [IAC DM]
JRST NTISER
; IAC AYT
WHOLIN: HRROI WHOBUF ; system who-line
WHO
SKIPA X,[440700,,WHOBUF]
WHOLN1: PUSHJ P,NETOCH
ILDB X
JUMPN WHOLN1
MOVE TTYLIN
TTYJOB
JUMPE WHOLN3
HRL
HRRI WHOBUF
WHO
SKIPA X,[440700,,WHOBUF]
WHOLN2: PUSHJ P,NETOCH
ILDB X
JUMPN WHOLN2
WHOLN3: PUSHJ P,NETSND
JRST NTISER
; IAC EC/IAC EL
DELCHR: SKIPA B,[177] ; rubout
DELLIN: MOVEI B,↑U ; control-U
JRST PTYSND
; IAC DO/DONT
DOSR: PUSHJ P,OPTMSG
CAIN TRNBIN ; binary from host
JRST [ SKIPE TRBINP ; catch protocol loops
JRST NTISER
SETOM TRBINP
TELCMD [IAC WILL TRNBIN]
JRST NTISER]
CAIN ECHO ; remote echo (what a win!)
JRST [ HRROI ECHON
TTYSET
SKIPE ECHOP ; catch protocol loops
JRST NTISER
SETOM ECHOP
TELCMD [IAC WILL ECHO]
JRST NTISER] ; command, we always accept it
CAIN SUPRGA ; suppress GA?
JRST [ SKIPE SUPGAP ; command or reply?
JRST NTISER
SETOM SUPGAP
TELCMD [IAC WILL SUPRGA]
JRST NTISER]
CAIN LOGOUT ; hairy MRC LOGOUT option?
JRST [ SETOM NODETP
TELCMD [IAC WILL LOGOUT]; we may be the only place that has it!
MOVEI X,[ASCIZ/Bye
/]
PUSHJ P,SNDMSG
JRST SUICID]
; Not an option we like, refuse it
PUSH P,
OUTSTR [ASCIZ/⊗IAC WONT/]
MOVEI IAC
PUSHJ P,NETOCH
MOVEI WONT
PUSHJ P,NETOCH
POP P,
PUSHJ P,OPTMSG
PUSHJ P,NETOCH
PUSHJ P,NETSND
JRST NTISER
DONTSR: PUSHJ P,OPTMSG
CAIN TRNBIN
JRST [ SKIPN TRBINP
JRST NTISER
SETZM TRBINP
TELCMD [IAC WONT TRNBIN]
JRST NTISER]
CAIN ECHO
JRST [ HRROI ECHOFF
TTYSET
SKIPN ECHOP
JRST NTISER
SETZM ECHOP ; back to lossage
TELCMD [IAC WONT ECHO]
JRST NTISER]
CAIN SUPRGA
SKIPL SUPGAP
JRST NTISER ; protocol violator
SETZM SUPGAP
TELCMD [IAC WONT SUPRGA]
JRST NTISER ; loser
; IAC WILL/WONT
WILLSR: PUSHJ P,OPTMSG
CAIN TRNBIN ; binary to host
JRST [ SKIPE RCBINP ; catch protocol loops
JRST NTISER
SETOM RCBINP
TELCMD [IAC DO TRNBIN]
JRST NTISER]
; Not an option we like, refuse it
PUSH P,
OUTSTR [ASCIZ/⊗IAC DONT/]
MOVEI IAC
PUSHJ P,NETOCH
MOVEI DONT
PUSHJ P,NETOCH
POP P,
PUSHJ P,OPTMSG
PUSHJ P,NETOCH
PUSHJ P,NETSND
JRST NTISER
WONTSR: PUSHJ P,OPTMSG
CAIN TRNBIN
SKIPN RCBINP
JRST NTISER
SETZM RCBINP
TELCMD [IAC DONT TRNBIN]
JRST NTISER
SUBTTL Subroutines
; WILL/WONT/DO/DONT option message
OPTMSG: CAIN EXOPL
JRST [ OUTSTR [ASCIZ/ EXOPL*
/]
POPJ P,]
OUTCHR [" ]
CAILE WDOMAX
RNDMSG: JRST [ IDIVI 100
ADDI "0
OUTCHR
IDIVI 10
ADDI 1,"0
OUTCHR 1
ADDI 2,"0
OUTCHR 2
OUTSTR [ASCIZ/*
/]
POPJ P,]
MOVE 1,
OUTSTR @WDOTAB(1)
OUTSTR [ASCIZ/*
/]
POPJ P,
; Send a message, b.p. in X
SNDMSG: TLOA X,440700 ; set up b.p.
MSGLUP: PUSHJ P,NETOCH
ILDB X
JUMPN MSGLUP ; continue until a null hit
JRST NETSND
; Here to suicide on network errors or idle timeout
INTDIE: INTMSK [0] ; no more interrupts
DEBREAK ; out of interrupt level
SUICID: OUTSTR [ASCIZ/Connection closed.
/]
SKIPE NODETP
JRST DIEDIE ; logout the guy
MOVE A,TTYLIN
TTYJOB A,
JUMPE A,DIEDIE
MOVE A,TTYLIN
MOVEI B,7
PTJOBX A ; clear PTY's input buffer
PTRD1S A ; slurp up stuff in buffer
CAIA
JRST .-2
MOVEI B,[.BYTE 9 ? 600 ? 600 ? "D ? "E ? "T ? "A ? "C ? "H ? ↑M ? ↑J ? 0]
PTWRS9 A
MOVEI 5.
SLEEP ; give it time to happen
PTRD1S A ; slurp up what's left in the buffer
JRST DIEDIE
JRST .-2
DIEDIE: RESET ? EXIT
...LIT: CONSTANTS
; Wonderful network routines
SVRRTS==-1 ; include server routines
ERRTNS==-1 ; include error routines
ERRHAN==-1 ; include automagic error handling
ERRINS==<JRST SUICID> ; error instruction
HSTTAB==-1 ; include host table magic
HSTSIX==-1 ; and alias name kludge
.INSRT NETWRK[NET,MRC]
END TELSER